home *** CD-ROM | disk | FTP | other *** search
/ Micromanía 92 / CDMM92_1.ISO / SOF 2 SDK / sof2sdk-101.msi / _92D6AC311BB48EBA344BBABC89DA6AB0 / _4577B3B9F04B4D07A7E73F9DAA1EE128 < prev    next >
Encoding:
Text File  |  2002-06-05  |  25.5 KB  |  1,051 lines

  1. // Copyright (C) 2001-2002 Raven Software
  2. //
  3. // cg_ents.c -- present snapshot entities, happens every single frame
  4.  
  5. #include "cg_local.h"
  6. #include "..\game\q_shared.h"
  7. #include "..\ghoul2\g2.h"
  8.  
  9. /*
  10. ======================
  11. CG_SetEntitySoundPosition
  12.  
  13. Also called by event processing code
  14. ======================
  15. */
  16. float *CG_SetEntitySoundPosition( centity_t *cent ) 
  17. {
  18.     static vec3_t v3Return;
  19.  
  20.     if ( cent->currentState.solid == SOLID_BMODEL ) 
  21.     {
  22.         vec3_t    origin;
  23.         float    *v;
  24.  
  25.         v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ];
  26.         VectorAdd( cent->lerpOrigin, v, origin );
  27.         trap_S_UpdateEntityPosition( cent->currentState.number, origin );
  28.         VectorCopy(origin, v3Return);
  29.     } 
  30.     else 
  31.     {
  32.         trap_S_UpdateEntityPosition( cent->currentState.number, cent->lerpOrigin );
  33.         VectorCopy(cent->lerpOrigin, v3Return);
  34.     }
  35.  
  36.     return v3Return;
  37. }
  38.  
  39. /*
  40. ==================
  41. CG_EntityEffects
  42.  
  43. Add continuous entity effects, like local entity emission and lighting
  44. ==================
  45. */
  46. static void CG_EntityEffects( centity_t *cent ) 
  47. {
  48.     sfxHandle_t        hSFX;
  49.     float            *v3Origin;
  50.  
  51.     // update sound origins
  52.     v3Origin = CG_SetEntitySoundPosition(cent);
  53.  
  54.     // add loop sound
  55.     if ( cent->currentState.loopSound ) 
  56.     {
  57.         // ambient soundset string index valid?
  58.         if (cent->currentState.eType == ET_MOVER &&    cent->currentState.mSoundSet)
  59.         {
  60.             hSFX = trap_AS_GetBModelSound( CG_ConfigString( CS_AMBIENT_SOUNDSETS + cent->currentState.mSoundSet), cent->currentState.loopSound);
  61.  
  62.             if (hSFX == -1)
  63.             {
  64.                 Com_Printf("CG_EntityEffects(): Bad SFX handle -1, ambient soundset not loaded?\n");
  65.             }
  66.             else
  67.             {
  68.                 trap_S_AddLoopingSound( cent->currentState.number, v3Origin/*cent->lerpOrigin*/, vec3_origin, hSFX, CHAN_AUTO );            
  69.             }
  70.         }
  71.         else
  72.         {
  73.             if (cent->currentState.eType != ET_SPEAKER) 
  74.             {
  75.                 trap_S_AddLoopingSound( 
  76.                     cent->currentState.number, 
  77.                     cent->lerpOrigin, 
  78.                     vec3_origin, 
  79.                     0,
  80.                     cgs.gameSounds[ cent->currentState.loopSound ] );
  81.             } 
  82.             else 
  83.             {
  84.                 trap_S_AddRealLoopingSound( 
  85.                     cent->currentState.number, 
  86.                     cent->lerpOrigin, 
  87.                     vec3_origin, 
  88.                     ((float)cent->currentState.time2) / 1000.0f,
  89.                     cgs.gameSounds[ cent->currentState.loopSound ] );
  90.             }
  91.         }
  92.     }
  93. }
  94.  
  95. /*
  96. ==================
  97. CG_SetGhoul2Info
  98. ==================
  99. */
  100. void CG_SetGhoul2Info( refEntity_t *ent, centity_t *cent)
  101. {
  102.     ent->ghoul2 = cent->ghoul2;
  103.     VectorCopy( cent->modelScale, ent->modelScale);
  104.     ent->radius = cent->radius + 256;
  105.     VectorCopy (cent->lerpAngles, ent->angles);
  106. }
  107.  
  108. /*
  109. ==================
  110. CG_SetGhoul2Info
  111.  
  112. Position an entity based on the bolt point of a ghoul2 model
  113. ==================
  114. */
  115. qboolean G2_PositionEntityOnBolt (
  116.     refEntity_t *ent, 
  117.     void        *ghoul2, 
  118.     int            modelIndex, 
  119.     int            boltIndex, 
  120.     vec3_t        origin, 
  121.     vec3_t        angles, 
  122.     vec3_t        modelScale
  123.     )
  124. {
  125.     qboolean boltMatrixOK = qfalse;
  126.     mdxaBone_t boltMatrix;
  127.  
  128.     if (boltIndex < 0)
  129.         return boltMatrixOK;
  130.  
  131.     boltMatrixOK = trap_G2API_GetBoltMatrix(ghoul2, modelIndex, boltIndex, &boltMatrix,
  132.                                             angles, origin, cg.time, cgs.gameModels, modelScale);
  133.  
  134.     if (boltMatrixOK)
  135.     {    
  136.         // set up the axis and origin
  137.         ent->origin[0] = boltMatrix.matrix[0][3];
  138.         ent->origin[1] = boltMatrix.matrix[1][3];
  139.         ent->origin[2] = boltMatrix.matrix[2][3];
  140.  
  141.         ent->axis[0][0] = boltMatrix.matrix[0][0];
  142.         ent->axis[0][1] = boltMatrix.matrix[1][0];
  143.         ent->axis[0][2] = boltMatrix.matrix[2][0];
  144.  
  145.         ent->axis[1][0] = boltMatrix.matrix[0][1];
  146.         ent->axis[1][1] = boltMatrix.matrix[1][1];
  147.         ent->axis[1][2] = boltMatrix.matrix[2][1];
  148.  
  149.         ent->axis[2][0] = boltMatrix.matrix[0][2];
  150.         ent->axis[2][1] = boltMatrix.matrix[1][2];
  151.         ent->axis[2][2] = boltMatrix.matrix[2][2];
  152.     }
  153.  
  154.     return boltMatrixOK;
  155. }
  156.  
  157. /*
  158. ==================
  159. CG_ScaleModelAxis
  160. ==================
  161. */
  162. void CG_ScaleModelAxis(refEntity_t    *ent)
  163. {        
  164.     // scale the model should we need to
  165.     if (ent->modelScale[0] && ent->modelScale[0] != 1.0f)
  166.     {
  167.         VectorScale( ent->axis[0], ent->modelScale[0] , ent->axis[0] );
  168.         ent->nonNormalizedAxes = qtrue;
  169.     }
  170.     if (ent->modelScale[1] && ent->modelScale[1] != 1.0f)
  171.     {
  172.         VectorScale( ent->axis[1], ent->modelScale[1] , ent->axis[1] );
  173.         ent->nonNormalizedAxes = qtrue;
  174.     }
  175.     if (ent->modelScale[2] && ent->modelScale[2] != 1.0f)
  176.     {
  177.         VectorScale( ent->axis[2], ent->modelScale[2] , ent->axis[2] );
  178.         ent->nonNormalizedAxes = qtrue;
  179.     }
  180. }
  181.  
  182. /*
  183. ==================
  184. CG_General
  185. ==================
  186. */
  187. static void CG_General( centity_t *cent ) 
  188. {
  189.     refEntity_t            ent;
  190.     entityState_t        *s1;
  191.  
  192.     s1 = ¢->currentState;
  193.  
  194.     // Dont draw any player models when the round has ended
  195.     if ( cg.snap->ps.pm_type == PM_INTERMISSION )
  196.     {
  197.         return;
  198.     }
  199.  
  200.     // if set to invisible, skip
  201.     if ((!s1->modelindex) && !(trap_G2_HaveWeGhoul2Models(cent->ghoul2))) 
  202.     {
  203.         return;
  204.     }
  205.  
  206.     memset (&ent, 0, sizeof(ent));
  207.  
  208.     // set frame
  209.     ent.frame = s1->frame;
  210.     ent.oldframe = ent.frame;
  211.     ent.backlerp = 0;
  212.  
  213.     CG_SetGhoul2Info(&ent, cent);
  214.  
  215.     VectorCopy( cent->lerpOrigin, ent.origin);
  216.     VectorCopy( cent->lerpOrigin, ent.oldorigin);
  217.  
  218.     ent.hModel = cgs.gameModels[s1->modelindex];
  219.  
  220.     // player model
  221.     if (s1->number == cg.snap->ps.clientNum) 
  222.     {
  223.         ent.renderfx |= RF_THIRD_PERSON;    // only draw from mirrors
  224.     }
  225.  
  226.     // Bodies need shadows under them
  227.     if ( cent->currentState.eType == ET_BODY && !(cent->currentState.eFlags&EF_NOSHADOW))
  228.     {
  229.         CG_PlayerShadow( cent, &ent.shadowPlane );
  230.  
  231.         if ( cg_shadows.integer == 3 && ent.shadowPlane ) 
  232.         {
  233.             ent.renderfx |= RF_SHADOW_PLANE;
  234.         }
  235.     }
  236.  
  237.     ent.renderfx |= RF_MINLIGHT;
  238.  
  239.     // convert angles to axis
  240.     AnglesToAxis( cent->lerpAngles, ent.axis );
  241.  
  242.     // add to refresh list
  243.     trap_R_AddRefEntityToScene (&ent);
  244. }
  245.  
  246. /*
  247. ==================
  248. CG_Speaker
  249.  
  250. Speaker entities can automatically play sounds
  251. ==================
  252. */
  253. static void CG_Speaker( centity_t *cent ) 
  254. {
  255.     if ( ! cent->currentState.clientNum ) 
  256.     {    
  257.         // not auto triggering
  258.         return;        
  259.     }
  260.  
  261.     if ( cg.time < cent->miscTime ) 
  262.     {
  263.         return;
  264.     }
  265.  
  266.     trap_S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.gameSounds[cent->currentState.eventParm], -1, -1 );
  267.  
  268.     cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom();
  269. }
  270.  
  271. /*
  272. ==================
  273. CG_Item
  274. ==================
  275. */
  276. static void CG_Item( centity_t *cent ) 
  277. {
  278.     refEntity_t        ent;
  279.     entityState_t    *es;
  280.     gitem_t            *item;
  281.     int                msec;
  282.     float            frac;
  283.     weaponInfo_t    *wi;
  284.  
  285.     es = ¢->currentState;
  286.     if ( es->modelindex >= bg_numItems ) 
  287.     {
  288.         Com_Error( ERR_FATAL, "Bad item index %i on entity", es->modelindex );
  289.     }
  290.  
  291.     // if set to invisible, skip
  292.     if ( (!es->modelindex ) || ( es->eFlags & EF_NODRAW ) ) 
  293.     {
  294.         return;
  295.     }    
  296.  
  297.     if ( !cg_items[es->modelindex].registered )
  298.     {
  299.         CG_RegisterItemVisuals ( es->modelindex);
  300.     }
  301.  
  302.     item = &bg_itemlist[ es->modelindex ];
  303.     
  304.     // Track gametype items for the radar
  305.     if ( es->modelindex >= MODELINDEX_GAMETYPE_ITEM && es->modelindex <= MODELINDEX_GAMETYPE_ITEM_2 )
  306.     {
  307.         cg.radarEntities[cg.radarEntityCount++] = cent;
  308.     }
  309.  
  310.     // Simple items draws sprites only 
  311.     if ( cg_simpleItems.integer && item->giType != IT_GAMETYPE && cg_items[es->modelindex].mSimpleIcon) 
  312.     {
  313.         memset( &ent, 0, sizeof( ent ) );
  314.         ent.reType = RT_SPRITE;
  315.         VectorCopy( cent->lerpOrigin, ent.origin );
  316.         ent.radius = 8;
  317.         ent.customShader = cg_items[es->modelindex].mSimpleIcon;
  318.         ent.shaderRGBA[0] = 255;
  319.         ent.shaderRGBA[1] = 255;
  320.         ent.shaderRGBA[2] = 255;
  321.         ent.shaderRGBA[3] = 255;
  322.         trap_R_AddRefEntityToScene(&ent);
  323.         return;
  324.     }
  325.  
  326.     memset (&ent, 0, sizeof(ent));
  327.  
  328.     if (cent->currentState.eFlags & EF_ANGLE_OVERRIDE)
  329.     {
  330.         AnglesToAxis ( cent->currentState.angles, ent.axis );
  331.     }
  332.     else
  333.     {
  334.         vec3_t angles;
  335.  
  336.         VectorCopy ( cent->currentState.angles, angles );
  337.         if ( item->giType == IT_WEAPON )
  338.         {
  339.             if ( item->giTag == WP_MM1_GRENADE_LAUNCHER )
  340.             {
  341.                 angles[ROLL] += 135;
  342.                 cent->lerpOrigin[2] += 4;
  343.             }
  344.             else
  345.             {
  346.                 angles[ROLL] += 90;
  347.             }
  348.         }
  349.  
  350.         AnglesToAxis ( angles, ent.axis );
  351.     }
  352.  
  353.     wi = NULL;
  354.  
  355.     // the weapons have their origin where they attatch to player
  356.     // models, so we need to offset them or they will rotate
  357.     // eccentricly
  358.     if (!(cent->currentState.eFlags & EF_ANGLE_OVERRIDE))
  359.     {
  360.         if ( item->giType == IT_WEAPON ) 
  361.         {
  362.             wi = &cg_weapons[item->giTag];
  363.             cent->lerpOrigin[0] -= 
  364.                 wi->weaponMidpoint[0] * ent.axis[0][0] +
  365.                 wi->weaponMidpoint[1] * ent.axis[1][0] +
  366.                 wi->weaponMidpoint[2] * ent.axis[2][0];
  367.             cent->lerpOrigin[1] -= 
  368.                 wi->weaponMidpoint[0] * ent.axis[0][1] +
  369.                 wi->weaponMidpoint[1] * ent.axis[1][1] +
  370.                 wi->weaponMidpoint[2] * ent.axis[2][1];
  371.             cent->lerpOrigin[2] -= 
  372.                 wi->weaponMidpoint[0] * ent.axis[0][2] +
  373.                 wi->weaponMidpoint[1] * ent.axis[1][2] +
  374.                 wi->weaponMidpoint[2] * ent.axis[2][2];
  375.         }
  376.  
  377.         // an extra height boost
  378.         if ( item->giType == IT_WEAPON )
  379.         {
  380.             cent->lerpOrigin[2] -= 14;
  381.         }
  382.         else
  383.         {
  384.             cent->lerpOrigin[2] -= 15;
  385.         }
  386.     }
  387.  
  388.     ent.hModel = cg_items[es->modelindex].models[0];
  389.     ent.ghoul2 = cg_items[es->modelindex].g2Models[0];
  390.     ent.radius = cg_items[es->modelindex].radius[0];
  391.  
  392.     if ( ent.radius <= 0 )
  393.     {
  394.         ent.radius = 256;
  395.     }
  396.  
  397.     VectorCopy (cent->lerpAngles, ent.angles);
  398.     VectorCopy( cent->lerpOrigin, ent.origin);
  399.     VectorCopy( cent->lerpOrigin, ent.oldorigin);
  400.  
  401.     ent.nonNormalizedAxes = qfalse;
  402.  
  403.     // if just respawned, slowly scale up
  404.     msec = cg.time - cent->miscTime;
  405.     frac = 1.0;
  406.  
  407.     // items without glow textures need to keep a minimum light value
  408.     // so they are always visible
  409. //    if ( ( item->giType == IT_WEAPON ) || ( item->giType == IT_ARMOR ) || (item->giType == IT_GAMETYPE ) ||
  410. //         ( item->giType == IT_HEALTH) ) 
  411.     {
  412.         ent.renderfx |= RF_MINLIGHT;
  413.     }
  414.  
  415.     // add to refresh list
  416.     trap_R_AddRefEntityToScene(&ent);
  417. }
  418.  
  419. /*
  420. ===============
  421. CG_Missile
  422. ===============
  423. */
  424. static void CG_Missile( centity_t *cent ) 
  425. {
  426.     refEntity_t                ent;
  427.     entityState_t            *s1;
  428.     const weaponInfo_t        *weapon;
  429.     const attackInfo_t        *attack;
  430.  
  431.     s1 = ¢->currentState;
  432.     if ( s1->weapon > WP_NUM_WEAPONS ) 
  433.     {
  434.         s1->weapon = 0;
  435.     }
  436.     weapon = &cg_weapons[s1->weapon];
  437.  
  438.     // calculate the axis
  439.     VectorCopy( s1->angles, cent->lerpAngles);
  440.  
  441.     if ( s1->weapon == WP_KNIFE )
  442.     {
  443.         cent->lerpAngles[ROLL] += (float)cg.time * 1.75f;
  444.     }
  445.  
  446.     // Determine which attack to use
  447.     if ( cent->currentState.eFlags & EF_ALT_FIRING )
  448.     {
  449.         attack = &weapon->attack[ATTACK_ALTERNATE];
  450.     }
  451.     else
  452.     {
  453.         attack = &weapon->attack[ATTACK_NORMAL];
  454.     }
  455.  
  456.     // add trails
  457.     if ( attack->missileTrailFunc )  
  458.     {
  459.         if ( cg.time > cent->miscTime  )
  460.         {
  461.             attack->missileTrailFunc( cent, s1->weapon );
  462.             cent->miscTime = cg.time + 25;
  463.         }
  464.     }
  465.  
  466.     // add dynamic light
  467.     if ( attack->missileDlight ) 
  468.     {
  469.         trap_R_AddLightToScene(cent->lerpOrigin, 
  470.                                attack->missileDlight, 
  471.                                attack->missileDlightColor[0], 
  472.                                attack->missileDlightColor[1], 
  473.                                attack->missileDlightColor[2] );
  474.     }
  475.  
  476.     // add missile sound
  477.     if ( attack->missileSound ) 
  478.     {
  479.         vec3_t    velocity;
  480.  
  481.         BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.time, velocity );
  482.  
  483.         trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, velocity, 500, attack->missileSound );
  484.     }
  485.  
  486.     //Don't draw something without a model
  487.     if (!trap_G2_HaveWeGhoul2Models( attack->missileG2Model) )
  488.     {
  489.         return;
  490.     }
  491.  
  492.     // create the render entity
  493.     memset (&ent, 0, sizeof(ent));
  494.     VectorCopy( cent->lerpOrigin, ent.origin);
  495.     VectorCopy( cent->lerpOrigin, ent.oldorigin);
  496.     if (0 == cent->modelScale[0] && 0 == cent->modelScale[1] && 0 == cent->modelScale[2])
  497.     {
  498.         VectorSet( cent->modelScale, 1, 1, 1);
  499.     }
  500.  
  501.     CG_SetGhoul2Info(&ent, cent);  
  502.  
  503.     // flicker between two skins
  504.     ent.skinNum = cg.clientFrame & 1;
  505.     ent.renderfx = RF_NOSHADOW;
  506.     ent.ghoul2 = attack->missileG2Model;
  507.     
  508.     // spin as it moves
  509.     if ( !(s1->eFlags&EF_ANGLE_OVERRIDE) && s1->apos.trType != TR_INTERPOLATE )
  510.     {
  511.         // convert direction of travel into axis
  512.         if ( VectorNormalize2( s1->pos.trDelta, ent.axis[0] ) == 0 ) 
  513.         {
  514.             ent.axis[0][2] = 1;
  515.         }
  516.  
  517.         // spin as it moves
  518.         if ( s1->pos.trType != TR_STATIONARY ) 
  519.         {
  520.             RotateAroundDirection( ent.axis, cg.time * 0.25f );
  521.         } 
  522.         else 
  523.         {
  524.             RotateAroundDirection( ent.axis, (float)s1->time );
  525.         }
  526.     }
  527.     else
  528.     {
  529.         AnglesToAxis( cent->lerpAngles, ent.axis );
  530.     }
  531.  
  532.     // add to refresh list
  533.     trap_R_AddRefEntityToScene( &ent );
  534. }
  535.  
  536. /*
  537. ===============
  538. CG_Mover
  539. ===============
  540. */
  541. static void CG_Mover( centity_t *cent ) 
  542. {
  543.     refEntity_t            ent;
  544.     entityState_t        *s1;
  545.  
  546.     s1 = ¢->currentState;
  547.  
  548.     // create the render entity
  549.     memset (&ent, 0, sizeof(ent));
  550.     VectorCopy( cent->lerpOrigin, ent.origin);
  551.     VectorCopy( cent->lerpOrigin, ent.oldorigin);
  552.     AnglesToAxis( cent->lerpAngles, ent.axis );
  553.  
  554.     ent.renderfx = RF_NOSHADOW;
  555.  
  556.     CG_SetGhoul2Info(&ent, cent);  
  557.  
  558.     // flicker between two skins (FIXME?)
  559.     ent.skinNum = ( cg.time >> 6 ) & 1;
  560.  
  561.     // get the model, either as a bmodel or a modelindex
  562.     if ( s1->solid == SOLID_BMODEL ) 
  563.     {
  564.         ent.hModel = cgs.inlineDrawModel[s1->modelindex];
  565.     } 
  566.     else 
  567.     {
  568.         ent.hModel = cgs.gameModels[s1->modelindex];
  569.     }
  570.  
  571.     // add to refresh list
  572.     trap_R_AddRefEntityToScene(&ent);
  573.  
  574.     // add the secondary model
  575.     if ( s1->modelindex2 ) 
  576.     {
  577.         ent.skinNum = 0;
  578.         ent.hModel = cgs.gameModels[s1->modelindex2];
  579.         trap_R_AddRefEntityToScene(&ent);
  580.     }
  581. }
  582.  
  583. /*
  584. ===============
  585. CG_Beam
  586.  
  587. Also called as an event
  588. ===============
  589. */
  590. void CG_Beam( centity_t *cent ) 
  591. {
  592.     refEntity_t            ent;
  593.     entityState_t        *s1;
  594.  
  595.     s1 = ¢->currentState;
  596.  
  597.     // create the render entity
  598.     memset (&ent, 0, sizeof(ent));
  599.     VectorCopy( s1->pos.trBase, ent.origin );
  600.     VectorCopy( s1->origin2, ent.oldorigin );
  601.     AxisClear( ent.axis );
  602.     ent.reType = RT_BEAM;
  603.  
  604.     ent.renderfx = RF_NOSHADOW;
  605.  
  606.     CG_SetGhoul2Info(&ent, cent);  
  607.  
  608.     // add to refresh list
  609.     trap_R_AddRefEntityToScene(&ent);
  610. }
  611.  
  612.  
  613. /*
  614. ===============
  615. CG_Portal
  616. ===============
  617. */
  618. static void CG_Portal( centity_t *cent ) 
  619. {
  620.     refEntity_t            ent;
  621.     entityState_t        *s1;
  622.  
  623.     s1 = ¢->currentState;
  624.  
  625.     // create the render entity
  626.     memset (&ent, 0, sizeof(ent));
  627.     VectorCopy( cent->lerpOrigin, ent.origin );
  628.     VectorCopy( s1->origin2, ent.oldorigin );
  629.     ByteToDir( s1->eventParm, ent.axis[0] );
  630.     PerpendicularVector( ent.axis[1], ent.axis[0] );
  631.  
  632.     // negating this tends to get the directions like they want
  633.     // we really should have a camera roll value
  634.     VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] );
  635.  
  636.     CrossProduct( ent.axis[0], ent.axis[1], ent.axis[2] );
  637.     ent.reType = RT_PORTALSURFACE;
  638.     ent.oldframe = s1->gametypeitems;
  639.     ent.frame = s1->frame;        // rotation speed
  640.     ent.skinNum = s1->clientNum/256.0 * 360;    // roll offset
  641.  
  642.     CG_SetGhoul2Info(&ent, cent);  
  643.  
  644.     // add to refresh list
  645.     trap_R_AddRefEntityToScene(&ent);
  646. }
  647.  
  648.  
  649. /*
  650. =========================
  651. CG_AdjustPositionForMover
  652.  
  653. Also called by client movement prediction code
  654. =========================
  655. */
  656. void CG_AdjustPositionForMover( 
  657.     const vec3_t    in, 
  658.     int                moverNum, 
  659.     int                fromTime, 
  660.     int                toTime, 
  661.     vec3_t            out 
  662.     ) 
  663. {
  664.     centity_t    *cent;
  665.     vec3_t    oldOrigin, origin, deltaOrigin;
  666.     vec3_t    oldAngles, angles, deltaAngles;
  667.  
  668.     if ( moverNum <= 0 || moverNum >= ENTITYNUM_MAX_NORMAL ) 
  669.     {
  670.         VectorCopy( in, out );
  671.         return;
  672.     }
  673.  
  674.     cent = CG_GetEntity ( moverNum );
  675.     if ( cent->currentState.eType != ET_MOVER ) 
  676.     {
  677.         VectorCopy( in, out );
  678.         return;
  679.     }
  680.  
  681.     BG_EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin );
  682.     BG_EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles );
  683.  
  684.     BG_EvaluateTrajectory( ¢->currentState.pos, toTime, origin );
  685.     BG_EvaluateTrajectory( ¢->currentState.apos, toTime, angles );
  686.  
  687.     VectorSubtract( origin, oldOrigin, deltaOrigin );
  688.     VectorSubtract( angles, oldAngles, deltaAngles );
  689.  
  690.     VectorAdd( in, deltaOrigin, out );
  691.  
  692.     // FIXME: origin change when on a rotating object
  693. }
  694.  
  695. /*
  696. =============================
  697. CG_InterpolateEntityPosition
  698. =============================
  699. */
  700. static void CG_InterpolateEntityPosition( centity_t *cent ) 
  701. {
  702.     vec3_t        current;
  703.     vec3_t        next;
  704.     float        f;
  705.  
  706.     // it would be an internal error to find an entity that interpolates without
  707.     // a snapshot ahead of the current one
  708.     if ( cg.nextSnap == NULL ) 
  709.     {
  710.         Com_Error( ERR_FATAL, "CG_InterpoateEntityPosition: cg.nextSnap == NULL" );
  711.     }
  712.  
  713.     f = cg.frameInterpolation;    
  714.  
  715.     // this will linearize a sine or parabolic curve, but it is important
  716.     // to not extrapolate player positions if more recent data is available
  717.     BG_EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current );
  718.     BG_EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next );
  719.  
  720.     cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] );
  721.     cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] );
  722.     cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] );
  723.  
  724.     BG_EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current );
  725.     BG_EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next );
  726.  
  727.     cent->lerpAngles[0] = LerpAngle( current[0], next[0], f );
  728.     cent->lerpAngles[1] = LerpAngle( current[1], next[1], f );
  729.     cent->lerpAngles[2] = LerpAngle( current[2], next[2], f );
  730.  
  731.     BG_EvaluateTrajectoryDelta( ¢->currentState.pos, cg.snap->serverTime, current );
  732.     BG_EvaluateTrajectoryDelta( ¢->nextState.pos, cg.nextSnap->serverTime, next );
  733.     cent->lerpVelocity[0] = current[0] + f * ( next[0] - current[0] );
  734.     cent->lerpVelocity[1] = current[1] + f * ( next[1] - current[1] );
  735.     cent->lerpVelocity[2] = current[2] + f * ( next[2] - current[2] );
  736.  
  737.     cent->lerpLeanOffset = cent->currentState.leanOffset + (int)(f * (float)(cent->nextState.leanOffset - cent->currentState.leanOffset)) - LEAN_OFFSET;
  738. }
  739.  
  740. /*
  741. ===============
  742. CG_CalcEntityLerpPositions
  743. ===============
  744. */
  745. void CG_CalcEntityLerpPositions( centity_t *cent ) 
  746. {
  747.     // if this player does not want to see extrapolated players
  748.     if ( !cg_smoothClients.integer ) 
  749.     {
  750.         // make sure the clients use TR_INTERPOLATE
  751.         if ( cent->currentState.number < MAX_CLIENTS ) 
  752.         {
  753.             cent->currentState.pos.trType = TR_INTERPOLATE;
  754.             cent->nextState.pos.trType = TR_INTERPOLATE;
  755.         }
  756.     }
  757.  
  758.     if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) 
  759.     {
  760.         CG_InterpolateEntityPosition( cent );
  761.         return;
  762.     }
  763.  
  764.     // first see if we can interpolate between two snaps for
  765.     // linear extrapolated clients
  766.     if ( cent->interpolate                                 && 
  767.          cent->currentState.pos.trType == TR_LINEAR_STOP &&
  768.          cent->currentState.number < MAX_CLIENTS            ) 
  769.     {
  770.         CG_InterpolateEntityPosition( cent );
  771.         return;
  772.     }
  773.  
  774.     // just use the current frame and evaluate as best we can
  775.     BG_EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin );
  776.     BG_EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles );
  777.     VectorCopy ( cent->currentState.pos.trDelta, cent->lerpVelocity );
  778.     cent->lerpLeanOffset = cent->currentState.leanOffset - LEAN_OFFSET;
  779.  
  780.     // adjust for riding a mover if it wasn't rolled into the predicted
  781.     // player state
  782.     if ( cent->currentState.number != cg.predictedPlayerState.clientNum )
  783.     {
  784.         CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum, 
  785.                                    cg.snap->serverTime, cg.time, cent->lerpOrigin );
  786.     }
  787. }
  788.  
  789. /*
  790. ===============
  791. CG_DebugCylinder
  792. ===============
  793. */
  794. void CG_DebugCylinder ( centity_t* cent )
  795. {
  796.     refEntity_t ref;
  797.     vec3_t        normal;
  798.  
  799.     memset( &ref, 0, sizeof(ref) );
  800.     VectorCopy ( cent->currentState.origin, ref.origin );
  801.     VectorCopy ( cent->currentState.origin, ref.oldorigin );
  802.     ref.origin[2] += 100;
  803.     ref.radius = cent->currentState.time2;
  804.     ref.rotation = cent->currentState.time2 + 10;
  805.     ref.customShader = trap_R_RegisterShader( "line" );
  806.     ref.reType = RT_CYLINDER;
  807.     
  808.     ref.shaderRGBA[0] = (unsigned char) (255.0f * g_color_table[ColorIndex(cent->currentState.time)][0]);
  809.     ref.shaderRGBA[1] = (unsigned char) (255.0f * g_color_table[ColorIndex(cent->currentState.time)][1]);
  810.     ref.shaderRGBA[2] = (unsigned char) (255.0f * g_color_table[ColorIndex(cent->currentState.time)][2]);
  811.     ref.shaderRGBA[3] = 255;
  812.  
  813.     VectorSubtract(ref.oldorigin, ref.origin, normal);
  814.     VectorNormalize(normal);
  815.     VectorCopy( normal, ref.axis[0] );
  816.     RotateAroundDirection( ref.axis, 0);
  817.  
  818.     trap_R_AddRefEntityToScene ( &ref ); 
  819. }
  820.  
  821. static void CG_AddLocalSet( centity_t *cent )
  822. {
  823.     cent->ambientSetTime = trap_AS_AddLocalSet( CG_ConfigString( CS_AMBIENT_SOUNDSETS + cent->currentState.mSoundSet/*localSoundSet*/), cg.refdef.vieworg, cent->lerpOrigin, cent->currentState.number, cent->ambientSetTime );
  824. }
  825.  
  826. /*
  827. ===============
  828. CG_AddCEntity
  829. ===============
  830. */
  831. static void CG_AddCEntity( centity_t *cent ) 
  832. {
  833.     // event-only entities will have been dealt with already
  834.     if ( cent->currentState.eType >= ET_EVENTS ) 
  835.     {
  836.         return;
  837.     }
  838.  
  839.     // calculate the current origin
  840.     CG_CalcEntityLerpPositions( cent );
  841.  
  842.     // add automatic effects
  843.     CG_EntityEffects( cent );
  844.  
  845.     // add local sound set if any
  846.     if ( cent->currentState.mSoundSet && cent->currentState.eType != ET_MOVER )
  847.     {
  848.         CG_AddLocalSet( cent );        
  849.     }
  850.  
  851.     // do this before we copy the data to refEnts
  852.     if (trap_G2_HaveWeGhoul2Models(cent->ghoul2))
  853.     {
  854.         trap_G2_SetGhoul2ModelIndexes(cent->ghoul2, cgs.gameModels, cgs.skins);
  855.     }
  856.  
  857.     switch ( cent->currentState.eType ) 
  858.     {
  859.         default:
  860.             Com_Error( ERR_FATAL, "Bad entity type: %i\n", cent->currentState.eType );
  861.             break;
  862.  
  863.         case ET_DAMAGEAREA:
  864.         case ET_INVISIBLE:
  865.         case ET_PUSH_TRIGGER:
  866.         case ET_TELEPORT_TRIGGER:
  867.         case ET_TERRAIN:
  868.             break;
  869.  
  870.         case ET_GENERAL:
  871.             CG_General( cent );
  872.             break;
  873.  
  874.         case ET_PLAYER:
  875.             CG_Player( cent );
  876.             break;
  877.  
  878.         case ET_ITEM:
  879.             CG_Item( cent );
  880.             break;
  881.  
  882.         case ET_MISSILE:
  883.             CG_Missile( cent );
  884.             break;
  885.  
  886.         case ET_MOVER:
  887.         case ET_WALL:
  888.             CG_Mover( cent );
  889.             break;
  890.  
  891.         case ET_BEAM:
  892.             CG_Beam( cent );
  893.             break;
  894.  
  895.         case ET_PORTAL:
  896.             CG_Portal( cent );
  897.             break;
  898.  
  899.         case ET_SPEAKER:
  900.             CG_Speaker( cent );
  901.             break;
  902.  
  903.         case ET_BODY:
  904.  
  905.             // If the bodies are to stay around forever and there
  906.             // is a body time set then see if we should hide it
  907.             if ( cg_bodyTime.integer && cent->currentState.time2 )
  908.             {
  909.                 int time = cg_bodyTime.integer * 1000;
  910.  
  911.                 if ( time < BODY_SINK_DELAY )
  912.                 {
  913.                     time = BODY_SINK_DELAY;
  914.                 }
  915.  
  916.                 time += cent->currentState.time2;
  917.  
  918.                 // Body is long gone
  919.                 if ( cg.time > time + BODY_SINK_TIME )
  920.                 {
  921.                     return;
  922.                 }
  923.  
  924.                 // Sink the body
  925.                 if ( cg.time > time )
  926.                 {
  927.                     cent->lerpOrigin[2] -= ((float)(cg.time - time) / (float)BODY_SINK_TIME) * (BODY_SINK_TIME/100.0f);
  928.  
  929.                     // Hack to stop shadows from showing up
  930.                     cent->currentState.eFlags |= EF_NOSHADOW;
  931.                 }
  932.             }
  933.  
  934.             // Dont show your own dead body unless in third person
  935.             if ( !cg.renderingThirdPerson )
  936.             {
  937.                 if ( cg.snap->ps.clientNum == cent->currentState.otherEntityNum )
  938.                 {
  939.                     if ( cg_entities[cg.snap->ps.clientNum].currentState.eFlags & EF_DEAD )
  940.                     {
  941.                         return;
  942.                     }
  943.                 }
  944.             }
  945.  
  946.             CG_General( cent );
  947.             break;
  948.  
  949.         case ET_DEBUG_CYLINDER:
  950.             CG_DebugCylinder ( cent );
  951.             break;
  952.     }
  953. }
  954.  
  955. /*
  956. ===============
  957. CG_AddPacketEntities
  958. ===============
  959. */
  960. void CG_AddPacketEntities( void ) 
  961. {
  962.     int            num;
  963.     centity_t    *cent;
  964.  
  965.     // set cg.frameInterpolation
  966.     if ( cg.nextSnap ) 
  967.     {
  968.         int        delta;
  969.  
  970.         delta = (cg.nextSnap->serverTime - cg.snap->serverTime);
  971.         if ( delta == 0 ) 
  972.         {
  973.             cg.frameInterpolation = 0;
  974.         } 
  975.         else 
  976.         {
  977.             cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta;
  978.         }
  979.     } 
  980.     else 
  981.     {
  982.         // actually, it should never be used, because 
  983.         // no entities should be marked as interpolating
  984.         cg.frameInterpolation = 0;                                    
  985.     }
  986.  
  987.     // the auto-rotating items will all have the same axis
  988.     cg.autoAngles[0] = 0;
  989.     cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0;
  990.     cg.autoAngles[2] = 0;
  991.  
  992.     cg.autoAnglesFast[0] = 0;
  993.     cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f;
  994.     cg.autoAnglesFast[2] = 0;
  995.  
  996.     AnglesToAxis( cg.autoAngles, cg.autoAxis );
  997.     AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast );
  998.  
  999.     // generate and add the entity from the playerstate
  1000.  
  1001.     // add in the Ghoul2 stuff.
  1002. //    VectorCopy( cg_entities[ cg.snap->ps.clientNum].modelScale, cg.predictedPlayerEntity.modelScale);
  1003. //    cg.predictedPlayerEntity.radius = cg_entities[ cg.snap->ps.clientNum].radius;
  1004.  
  1005. //    num = cg_entitiescg.predictedPlayerEntity.currentState.number;
  1006.     BG_PlayerStateToEntityState( &cg.predictedPlayerState, 
  1007.                                  &cg_entities[cg.predictedPlayerState.clientNum].currentState, 
  1008.                                  qfalse );
  1009.  
  1010. /*
  1011.     // If the client number changes then we have to blow away our current model
  1012.     if ( num != cg.predictedPlayerEntity.currentState.number )
  1013.     {
  1014.         trap_G2API_CleanGhoul2Models ( &cg.predictedPlayerEntity.ghoul2 );
  1015.         cg.predictedPlayerEntity.pe.weaponModelSpot = 0;
  1016.         cg.predictedPlayerEntity.pe.weapon = 0;
  1017.         cg.predictedPlayerEntity.ghoul2 = NULL;
  1018.     }
  1019. */
  1020.  
  1021.     cg_entities[cg.predictedPlayerState.clientNum].interpolate = qfalse;
  1022.     CG_AddCEntity( &cg_entities[cg.predictedPlayerState.clientNum] );
  1023.  
  1024.     // lerp the non-predicted value for lightning gun origins
  1025. //    CG_CalcEntityLerpPositions( &cg_entities[ cg.snap->ps.clientNum ] );
  1026.  
  1027.     // Reset radar entities
  1028.     cg.radarEntityCount = 0;
  1029.  
  1030.     // add each entity sent over by the server
  1031.     for ( num = 0 ; num < cg.snap->numEntities ; num++ ) 
  1032.     {
  1033.         // Don't re-add ents that have been predicted.
  1034.         if (cg.snap->entities[ num ].number != cg.snap->ps.clientNum)
  1035.         {
  1036.             cent = CG_GetEntity ( cg.snap->entities[ num ].number ); 
  1037.             CG_AddCEntity( cent );
  1038.         }
  1039.     }
  1040.  
  1041.     for(num=0;num<cg_numpermanents;num++)
  1042.     {
  1043.         cent = cg_permanents[num];
  1044.         if (cent->currentValid)
  1045.         {
  1046.             CG_AddCEntity( cent );
  1047.         }
  1048.     }
  1049. }
  1050.  
  1051.